package com.foton.bpc.all.config.plaugins;

import com.foton.bpc.all.config.ProtocolConfig;
import com.foton.bpc.all.config.RefrenceConfig;
import com.foton.bpc.all.config.RegisterConfig;
import com.foton.bpc.all.config.ServiceConfig;
import com.foton.bpc.all.config.annotion.BpcRefrence;
import com.foton.bpc.all.config.annotion.BpcService;
import com.foton.bpc.all.remoting.Transport;
import com.foton.bpc.all.util.BootStrapManage;
import com.foton.bpc.all.util.SpIUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.lang.reflect.Field;
import java.net.SocketException;
import java.net.URI;
import java.net.URISyntaxException;

/**
 * @Author RenPu
 * @Date 2023/6/5 15:48
 * @Version 1.0
 * @Description: spring bean装载成功后，
 *              需要根据@BpcService注解进行区分，然后对@BpcService标注需要单独处理
 **/

@Slf4j
public class BpcPostProcessor implements ApplicationContextAware, InstantiationAwareBeanPostProcessor {


    ApplicationContext applicationContext;

    /**
     * 获取spring容器，上下文对象便于从容器种获取对象
     * @param applicationContext
     * @throws BeansException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext=applicationContext;
    }


    /**
     * 完成bean得装载，可以通过此方法针对bean做扩展处理  （spring中得所有bean,都会经过此方法）
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {

        //（服务提供者）   校验bean得类对象是否包含，自定义注解@BpcService
        if(bean.getClass().isAnnotationPresent(BpcService.class)){
            ServiceConfig config = new ServiceConfig();
            config.addRegisterConfigs(applicationContext.getBean(RegisterConfig.class));
            config.addProtocolConfigs(applicationContext.getBean(ProtocolConfig.class));
            config.setReference(bean);
            //解析标注在bean上得注解中，interfaceClass是否设置了参数，如果没设置参数则获取bean对应类接口得第一个
            BpcService bpcService = bean.getClass().getAnnotation(BpcService.class);
            if(void.class==bpcService.interfaceClass()){
                  config.setService(bean.getClass().getInterfaces()[0]);
            }else {
                //否则获取注解上，配置的参数值
                config.setService(bpcService.interfaceClass());
            }
              //准备暴露服务
              BootStrapManage.exportService(config);

            log.info("启动网络服务，接收请求！！！！");
//            //使用统一入口Transport来启动网络服务
//            ProtocolConfig protocolConfig = applicationContext.getBean(ProtocolConfig.class);
//            String transportName = protocolConfig.getTransport();//获取网络底层框架得配置，例如：netty or mina
//
//            //SPI 根据配置得configName，匹配选择对应扩展实现
//            Transport transport =(Transport) SpIUtils.getServiceImpl(transportName, Transport.class);

//            //使用netyy作为网络得通信基石
//            try {
//                transport.start(new URI("xxx://127.0.0.1:8996/"));
//            } catch (URISyntaxException e) {
//                e.printStackTrace();
//            }

        }

        /**
         * 服务调用者 核心处理逻辑
         */
        Field[] fields = bean.getClass().getDeclaredFields();
        //由于@BpcRefrence这个注解是作用在，类得成员变量上的,所以进行遍历检验
        for (Field field : fields) {
           try{
               if(!field.isAnnotationPresent(BpcRefrence.class)){
                   //如果不包含，则跳出当前循环，进行下一次的校验
                   continue;
               }
               RefrenceConfig refrenceConfig = new RefrenceConfig();
               refrenceConfig.addProtocolConfigs(applicationContext.getBean(ProtocolConfig.class));
               refrenceConfig.addRegisterConfigs(applicationContext.getBean(RegisterConfig.class));
               //封装被注解标注的类对象
               refrenceConfig.setService(field.getType());

               //获取客户端设置得负责均衡策略
               BpcRefrence annotation = field.getAnnotation(BpcRefrence.class);
               if(StringUtils.isNotBlank(annotation.loadBalance())){
                   //设置负载均衡策略
                   refrenceConfig.setLoadBalance(annotation.loadBalance());
               }

               Object refrenceBean = BootStrapManage.getRefrenceBean(refrenceConfig);
               field.set(bean,refrenceBean);  //将生成的代理对象，设置到容器中
               field.setAccessible(true);     //设置可见性
           }catch (Exception e){
               e.printStackTrace();
           }
        }

        return bean;
    }
}
